//Source file: D:\\WTK104\\apps\\Toddtris\\src\\com\\toddsoft\\toddtris\\midlet\\ToddtrisMIDlet.java

package com.toddsoft.toddtris.midlet;

import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Gauge;
import javax.microedition.lcdui.Choice;
import javax.microedition.lcdui.ChoiceGroup;
import javax.microedition.midlet.MIDlet;
import com.toddsoft.toddtris.model.WellListener;
import javax.microedition.lcdui.CommandListener;
import com.toddsoft.toddtris.model.Well;
import com.toddsoft.toddtris.model.HighScoreTable;
import com.toddsoft.toddtris.control.RepeatController;
import com.toddsoft.toddtris.control.simple.SimpleController;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Display;

public class ToddtrisMIDlet extends MIDlet implements WellListener, CommandListener {
        

    private static final String VERSION = "2.0.7";
    private static final int DEFAULT_SENSITIVITY = 165;
    private static final int MAX_LEVEL = 10;
    private static final int LEVEL_MULTIPLIER = 1;
    private static final int MAX_START_HEIGHT = 5;
    private static final int START_HEIGHT_MULTIPLIER = 3;

    private SensitivityForm sensForm;
    private GameSetupForm gameSetupForm;
    private SetGridForm setGridForm;

    /**
     * indicates whether well was stopped to show menus
     */
    private boolean suspendedWell = false;
    
    private Well well;
    private HighScoreTable marathonHst;
    private HighScoreTable twentyFiveLineHst;
    private HighScoreTable fortyLineHst;
    private ToddtrisCanvas toddtrisCanvas;
    private RepeatController controller;
    private Command pauseCommand = new Command ("Pause", Command.SCREEN, 1);
    private Command unpauseCommand = new Command ("Resume", Command.SCREEN, 1);
    private Command defineKeysCommand = new Command ("Define Keys", Command.SCREEN, 4);
    private Command resetKeysCommand = new Command ("Reset Keys", Command.SCREEN, 5);
    private Command showSensitivityCommand = new Command ("Set Sensitivity", Command.SCREEN, 6);
    private Command setGridCommand = new Command ("Set Grid", Command.SCREEN, 7);
    private Command updatedSensitivityCommand = new Command ("OK", Command.OK, 1);
    private Command updatedGridCommand = new Command ("OK", Command.OK, 1);
    private Command newGameCommand = new Command ("New Game", Command.SCREEN, 2);
    private Command startGameCommand = new Command ("Start Game", Command.OK, 1);

    /**
     * not pressed start yet
     */
    public ToddtrisMIDlet() {

        ToddtrisStorage ts = ToddtrisStorage.getInstance();
        /* try and load up the saved app state */
        try {
            byte[] bytes = ts.getWellState();
            if (bytes.length == 0) {
                well = new Well(0, 0, 0);
            } else {
                well = new Well(bytes);
            }
        } catch (Exception e) {
            //couldn't load well
            well = new Well(0, 0, 0);
        }         

        /* create the high score tables */
        byte[] bytes = ts.getMarathonHighScores();
        marathonHst = makeHst(0, bytes, well);
        bytes = ts.getTwentyFiveLineHighScores();
        twentyFiveLineHst = makeHst(25, bytes, well);
        bytes = ts.getFortyLineHighScores();
        fortyLineHst = makeHst(40, bytes, well);

        well.addListener(this);
        boolean useColour = Display.getDisplay(this).isColor();

        /* get the sensitivity */
        int sens = ts.getSensitivity(DEFAULT_SENSITIVITY);

        /* get the keys */
        int[] keys = ts.getKeys();

        /* showing the grid? */
        boolean showGrid = ts.getGridShowing();

        sensForm = new SensitivityForm(sens);
        gameSetupForm = new GameSetupForm();

        setGridForm = new SetGridForm(showGrid);

        this.controller = new RepeatController(new SimpleController(well),
                                               sens);

        HighScoreTable[] hsta = new HighScoreTable[]{marathonHst, 
                                                     twentyFiveLineHst, 
                                                     fortyLineHst};

        toddtrisCanvas = new ToddtrisCanvas(well, 
                                            controller, 
                                            keys, 
                                            useColour, 
                                            showGrid,
                                            hsta);

        /* add the commands to the canvas */
        this.updateMenus();
        toddtrisCanvas.setCommandListener(this);
    }

    private static HighScoreTable makeHst(int numLines, 
                                          byte[] bytes,
                                          Well well) {
        try {
            if (bytes == null || bytes.length == 0) {
                return new HighScoreTable(well,
                                          MAX_START_HEIGHT,
                                          START_HEIGHT_MULTIPLIER,
                                          MAX_LEVEL,
                                          LEVEL_MULTIPLIER,
                                          numLines);
            } else {
                return new HighScoreTable(well,
                                          MAX_START_HEIGHT,
                                          START_HEIGHT_MULTIPLIER,
                                          MAX_LEVEL,
                                          LEVEL_MULTIPLIER,
                                          numLines,
                                          bytes);
            }
        } catch (Exception e) {
            return makeHst(numLines, null, well);
        }
    }
    
    public void startApp() {
        /* show the welcome screen */
        Form welcomeForm = new Form("Toddtris v" + VERSION);
        welcomeForm.append(new StringItem(null,"Copyright 2004 Allan Todd. at@themightystags.com"));
        welcomeForm.addCommand(new Command("OK", Command.OK, 1));
        
        final MIDlet tm = this;
        welcomeForm.setCommandListener(new CommandListener() {
                public void commandAction(Command c, Displayable d) {
                    Display.getDisplay(tm).setCurrent(toddtrisCanvas);
                }
                });
        
        Display.getDisplay(this).setCurrent(welcomeForm);
    }
    
    public void pauseApp() {

        /* stop the well */
        well.stopWell();     
    }
    
    /**
     * @param unconditional
     */
    public void destroyApp(boolean unconditional) {

        /* if the game is in progress and not paused, pause it */
        well.stopWell();

        ToddtrisStorage ts = ToddtrisStorage.getInstance();

        /* save the well state */
        try {
            ts.setWellState(well.toByteArray());
        } catch (Exception e) {
            //couldn't write record
        }

        /* save the high scores */
        try {
            ts.setMarathonHighScores(marathonHst.toByteArray());
        } catch (Exception e) {
            //couldn't write record
        }
        try {
            ts.setTwentyFiveLineHighScores(twentyFiveLineHst.toByteArray());
        } catch (Exception e) {
            //couldn't write record
        }
        try {
            ts.setForyLineHighScores(fortyLineHst.toByteArray());
        } catch (Exception e) {
            //couldn't write record
        }

        /* copied from worm sample! */
        Display.getDisplay(this).setCurrent(null);     
    }
    
    /**
     * WellListener Methods
     */

    /*
     * @param well
     */
    public void gameOver(Well well) {
        this.updateMenus();
    }

    /**
     * @param well
     */
    public void complete(Well well) {
        this.updateMenus();     
    }
    
    /**
     * @param well
     */
    public void wellChanged(Well well) {
        // do nothing     
    }
    
    /**
     * @param well
     * @param linesMade
     */
    public void madeLines(Well well, int linesMade) {
        // do nothing     
    }
    
    /**
     * @param well
     */
    public void wellReset(Well well) {
        // do nothing     
    }
    
    /**
     * @param well
     */
    public void blockLanded(Well well) {
        // do nothing     
    }
    
    /**
     * @param c
     * @param d
     */
    public void commandAction(Command c, Displayable d) {
        if (c == this.pauseCommand) {
            controller.togglePause();
            this.updateMenus();

        } else if (c == this.unpauseCommand) {
            controller.togglePause();
            this.updateMenus();

        } else if (c == this.newGameCommand) {
            well.stopWell();
            Display.getDisplay(this).setCurrent(gameSetupForm);

        } else if (c == this.showSensitivityCommand) {
            // pause the well
            suspendedWell = well.isMoving();
            if (suspendedWell) {
                well.stopWell();
            }
            // show the sensitivity form
            Display.getDisplay(this).setCurrent(sensForm);

        } else if (c == this.updatedSensitivityCommand) {
            // get the sensitivity
            int sens = sensForm.getSensitivity();
            //change the sensitivity of the canvas
            controller.setSensitivity(sens);
            //try to store updated sensitivity
            try {
                ToddtrisStorage.getInstance().setSensitivity(sens);
            } catch (Exception e) {
                e.printStackTrace();
                // can't write record - never mind!
            }
            Display.getDisplay(this).setCurrent(toddtrisCanvas);

            // start well again if required
            if (suspendedWell) {
                well.startWell();
            }
        } else if (c == this.setGridCommand) {
            // pause the well
            suspendedWell = well.isMoving();
            if (suspendedWell) {
                well.stopWell();
            }
            // show the sensitivity form
            Display.getDisplay(this).setCurrent(this.setGridForm);

        } else if (c == this.updatedGridCommand) {
            
            boolean gridState = setGridForm.getGridState();

            //change the setting of the canvas
            toddtrisCanvas.setGrid(gridState);
            //try to store updated state
            try {
                ToddtrisStorage.getInstance().setGridShowing(gridState);
            } catch (Exception e) {
                e.printStackTrace();
                // can't write record - never mind!
            }
            Display.getDisplay(this).setCurrent(toddtrisCanvas);

            // start well again if required
            if (suspendedWell) {
                well.startWell();
            }
        } else if (c == this.startGameCommand) {

            well.updateChallengeSettings(gameSetupForm.getTargetLines(), 
                                         gameSetupForm.getStartHeight(),
                                         gameSetupForm.getLevel());

            well.reset();
            Display.getDisplay(this).setCurrent(toddtrisCanvas);
            well.startWell();
            updateMenus();

        } else if (c == this.defineKeysCommand) {
            Display.getDisplay(this).setCurrent(new DefineKeysCanvas(this));

        } else if (c == this.resetKeysCommand) {
            keysUpdated(new int[] {});

//        } else {
            //System.out.println("commmandAction(" + c + ", " + d + ")");
        }     
    }
    
    private void updateMenus() {
        if (well.isMoving()) {
            toddtrisCanvas.removeCommand(unpauseCommand);
            toddtrisCanvas.removeCommand(showSensitivityCommand);
            toddtrisCanvas.removeCommand(setGridCommand);
            toddtrisCanvas.removeCommand(defineKeysCommand);
            toddtrisCanvas.removeCommand(resetKeysCommand);
            toddtrisCanvas.removeCommand(newGameCommand);
            toddtrisCanvas.addCommand(pauseCommand);
        } else {
            toddtrisCanvas.addCommand(showSensitivityCommand);
            toddtrisCanvas.addCommand(setGridCommand);
            toddtrisCanvas.addCommand(defineKeysCommand);
            toddtrisCanvas.addCommand(resetKeysCommand);
            toddtrisCanvas.removeCommand(pauseCommand);
            toddtrisCanvas.addCommand(newGameCommand);

            /* 
             * if the game is in progess then offer the unpause option 
             */
            if (well.isInProgress()) {
                toddtrisCanvas.addCommand(unpauseCommand);
            } else {
                toddtrisCanvas.removeCommand(unpauseCommand);
            }
        }     
    }
    
    /**
     * @param keys
     */
    void keysUpdated(int[] keys) {
        toddtrisCanvas.setKeys(keys);
        Display.getDisplay(this).setCurrent(toddtrisCanvas);
        try {
            //System.out.println("attempting save");
            ToddtrisStorage.getInstance().setKeys(keys);
        } catch (Exception e) {
            //e.printStackTrace();
            // can't write record - never mind!
        }     
    }
    


    /* 
     * Classes for forms 
     */
    class SensitivityForm extends Form {
        private Gauge gauge;
        
        /**
         * @param sens
         */
        SensitivityForm(int sens) {
            super("Key Sensitivity");

            int normalisedSens = (int)(20 - ((sens - 30)/15));

            gauge = new Gauge("Sensitivity",
                              true,
                              20,
                              normalisedSens);
            this.append(gauge);
    
            this.addCommand(updatedSensitivityCommand);
    
            this.setCommandListener(ToddtrisMIDlet.this);         
        }
        
        /**
         * @return int
         */
        public int getSensitivity() {
            int sens = 30 + ((20 - gauge.getValue()) * 15);
            return sens;         
        }
    }

    class GameSetupForm extends Form {
        private ChoiceGroup gameTypeChoices;
        private Gauge levelGauge;
        private Gauge heightGauge;
        
        /**
         * @param sens
         */
        GameSetupForm() {
            super("Game Setup");

            int normalisedLevel 
                    = (int)(well.getLevel() 
                            / LEVEL_MULTIPLIER);

            levelGauge = new Gauge("Level",
                                    true,
                                    MAX_LEVEL,
                                    normalisedLevel);
            this.append(levelGauge);

            gameTypeChoices 
                    = new ChoiceGroup("Game Type",
                                      Choice.EXCLUSIVE,
                                      new String[] {"Marathon", "25 Lines", "40 Lines"},
                                      null);  
            /* set the correct game type */
            int selectedIndex = 0;
            if (well.getTargetLines() == 25) {
                selectedIndex = 1;
            } else if (well.getTargetLines() == 40) {
                selectedIndex = 2;
            }
            gameTypeChoices.setSelectedIndex(selectedIndex, true);

            this.append(gameTypeChoices);
    
            int normalisedHeight 
                    = (int)(well.getStartHeight() 
                            / START_HEIGHT_MULTIPLIER);

            heightGauge = new Gauge("Height",
                                    true,
                                    MAX_START_HEIGHT,
                                    normalisedHeight);
            this.append(heightGauge);

            this.addCommand(startGameCommand);
    
            this.setCommandListener(ToddtrisMIDlet.this);         
        }

        /**
         * @return int
         */
        public int getTargetLines() {
            switch (gameTypeChoices.getSelectedIndex()) {
            case 0:
                return 0;
            case 1:
                return 25;
            case 2:
                return 40;
            default:
                return 0;
            }
        }

        /**
         * @return int
         */
        public int getStartHeight() {
            return (heightGauge.getValue() 
                    * START_HEIGHT_MULTIPLIER);         
        }

        /**
         * @return int
         */
        public int getLevel() {
            return (levelGauge.getValue()
                    * LEVEL_MULTIPLIER);         
        }
    }

    class SetGridForm extends Form {
        private ChoiceGroup gridChoices;
        
        /**
         * @param sens
         */
        SetGridForm(boolean gridState) {
            super("Set Grid");

            gridChoices 
                    = new ChoiceGroup("Display Grid",
                                      Choice.EXCLUSIVE,
                                      new String[] {"Off", "On"},
                                      null);  

            gridChoices.setSelectedIndex(gridState ? 1 : 0,
                                         true);

            this.append(gridChoices);

            this.setCommandListener(ToddtrisMIDlet.this);         
            this.addCommand(updatedGridCommand);
        }
        
        /**
         * @return int
         */
        public boolean getGridState() {
            return (gridChoices.getSelectedIndex() == 1);         
        }
    }
}
